#include <string>
#include <iomanip>

#include "Log.h"
#include "Parallel/ParallelMPI.h"
#include "Time/WallTime.h"

#ifdef _WIN32
#include <direct.h>
#include <io.h>
#elif _LINUX
#include <stdarg.h>
#include <sys/stat.h>
#endif

#ifdef _WIN32
#define ACCESS _access
#define MKDIR(a) _mkdir((a))
#elif _LINUX
#define ACCESS access
#define MKDIR(a) mkdir((a), 0755)
#endif



namespace plog
{
    class NoFunctionFormatter
    {
    public:
        static util::nstring header()
        {
            return util::nstring();
        }

        static util::nstring format(const Record& record)
        {
            tm t;
            (util::localtime_s)(&t, &record.getTime().time);

            util::nostringstream ss;
            ss << t.tm_year + 1900 << "-" << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mon + 1 << PLOG_NSTR("-") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mday << PLOG_NSTR(" ");
            ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_sec << PLOG_NSTR(".") << std::setfill(PLOG_NSTR('0')) << std::setw(3) << record.getTime().millitm << PLOG_NSTR(" ");
            ss << std::setfill(PLOG_NSTR(' ')) << std::setw(5) << std::left << severityToString(record.getSeverity()) << PLOG_NSTR(" ");
            //ss << PLOG_NSTR("[") << record.getTid() << PLOG_NSTR("] ");
            //ss << PLOG_NSTR("[") << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR("] ");
            ss << record.getMessage() << PLOG_NSTR("\n");

            return ss.str();
        }
    };
}




Log::Log(ParallelMPI* pmpi)
{

    std::string log_file_name = "result/EasyPSim_proc" + std::to_string(pmpi->get_rank()) + ".log" ;


    //if log file exist, rename it to backup
    if (access(log_file_name.c_str(), 0) == 0)
    {
        std::string logFileNameOld = log_file_name;
        WallTime wallTime;
        std::string str = wallTime.getDateTimeString();
        logFileNameOld += str;
        std::cout << logFileNameOld <<std::endl;
        //rename(log_file_name.c_str(), logFileNameOld.c_str());
        remove(log_file_name.c_str());
    }


    //logging::add_file_log(log_file_name, keywords::auto_flush = true);
    //logging::core::get()->set_filter(logging::trivial::severity>=logging::trivial::info);


    //static plog::ColorConsoleAppender<plog::TxtFormatter> consolAppender;
    static plog::ColorConsoleAppender<plog::MessageOnlyFormatter> consolAppender;
    //static plog::RollingFileAppender<plog::TxtFormatter> fileAppender(log_file_name.c_str(), 8000, 3);
    static plog::RollingFileAppender<plog::NoFunctionFormatter> fileAppender(log_file_name.c_str(), 300000000, 3);

    if (pmpi->is_master())
    {
        if (ACCESS("result", 0) == -1)
        {
            MKDIR("result");
        }

        if (ACCESS("result", 0) == -1)
        {
            MKDIR("result");
        }
    }
    pmpi->barrier();

    if(pmpi->is_master())
    {
        plog::init(plog::debug, &fileAppender).addAppender(&consolAppender);
        //plog::init(plog::debug, &consolAppender);
    }
    else
    {
        plog::init(plog::debug, &fileAppender);
    }




    WallTime wallTime;

    time_t now = time(0);
    time_t future = wallTime.StringToDatetime(" 2023-12-31 23:59:59");
    //log_info << "now: " << now << " future: " << future;
    //log_info << "end: creating logger";
    if (now > future)
    {
        //exit(0);
    }




}
